Skip to main content

Value Contract Structure

Value Contract structure consists of the following parts:

Most Important
  • Composition - defines the data structure that is used to store data in the ledger database.
  • Services - defines the rules that are used to interact with the data in the ledger database.
  • Constructor - defines the constructor of the VC.
  • Data Model - defines the data types that are used to store records in compositions.
  • Permissions - defines the permissions that are required to execute the service.

Constructor​

Defines the constructor of the VC. The constructor is called when the VC is deployed to the ledger database.

class [[inery::contract("valuecontract")]] valuecontract : public contract {
public:
using contract::contract;
valuecontract(name receiver, name code, datastream<const char*> ds): contract(receiver, code, ds) {}
~valuecontract() {}
};

Data Model​

Defines the data structure of the VC. The data structure are custom types that are used to store data in the ledger database.
Support primitive types are :int, uint, float, double, string, bool, time_point, time_point_sec, block_timestamp, checksum256, checksum160, checksum512, public_key, signature, symbol, symbol_code, asset, extended_asset, name, account_name, permission_name Also supports custom types that are defined by the user and array of primitive or custom types.

struct  profile {
std::string name;
uint64_t age;
};

Compositions​

Compositions are similar to tables in a relational database. They are used to store indexed data in the ledger database. The composition is defined by the [[inery::table("table_name")]] attribute. or simply TABLE table_name macro.

Each composition has a primary key that is used to uniquely identify the data in the composition. The primary key is defined by the primary_key attribute. In example below, the primary key is the id field. Also we used vector of profiles to store nested in array data.

[[inery::table("group")]] 
struct group {
uint64_t id;
string group_name;
vector<profile> profiles;

uint64_t primary_key() const { return id; }
};
typedef inery::multi_index<"group"_n, group> groups_table;

Services​

Services are custom functions that can be used by the actions.
The services are defined by the [[inery::action("service_name")]] attribute. or simply ACTION service_name macro.

Service structrue :

  • [[inery::action("service_name")]] - defines the service name.
  • service_name(param_type param_name, ...) - defines the service name and entry parameters.
  • composition_name composition_instance(payer, scope) - defines the composition instance with payer and scope.
    • payer is the database that pays for the memory storage of the data in the composition.
    • scope is the account that owns the data in the composition.
  • Database Operations
    • find(primary_key) - finds the row in the composition with the given primary key.
    • emplace(payer, [&](auto& row) { ... }) - adds a new row to the composition.
    • modify(iterator, payer, [&](auto& row) { ... }) - modifies the row in the composition.
    • erase(iterator) - erases the row in the composition.
    • available_primary_key() - returns the next available primary key in the composition.

Create Composition Instance Example

[[inery::action("creategroup")]]
void creategroup(string group_name) {
groups_table groups(get_self(), get_self().value);
groups.emplace(get_self(), [&](auto& row) {
row.id = group.available_primary_key();
row.group_name = group_name;
});
}

Permissions​

Permissions are required to execute the actions. Also before permission check, databse checks if the action is allowed to be executed by the user.

reqire_auth - checks if the action is allowed to be executed by the user. check - checks if the condition is true.

In the examaple below, the addprofile action requires the get_self() permission to execute. get_self() is the database that deployed the VC. Also, the action checks if the profile age is greater than 18 and if the group exists.

Update Composition Instance Example

[[inery::action("addprofile")]]
void addprofile(uint64_t group_id, profile new_profile) {
require_auth(get_self());
check(new_profile.age > 18, "Profile age must be greater than 18");
groups_table groups(get_self(), get_self().value);
auto group = groups.find(group_id);
check(group != groups.end(), "Group does not exist");
groups.modify(group, get_self(), [&](auto& row) {
row.profiles.push_back(new_profile);
});
}